/*
 *
 * Copyright (C) 1999-2012 IFLYTEK Inc.All Rights Reserved.
 *
 * FileName：FileUtil.java
 *
 * Description：
 *
 * History：
 * Version   Author      Date            Operation
 * 1.0	  ljwang2   2016年8月8日上午11:23:18	       Create
 */
package com.xunji.standard.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * @author ljwang2
 * @version 1.0
 */
public class FileUtil {
    /**
     * 实例化当前日志操作类
     */
    public static Logger logger = LoggerFactory.getLogger(FileUtil.class);

    private final static String fileStoreTempPath = "./tempzip/";

    /**
     * @param destFileName String
     * @return boolean
     * @description 创建文件
     * @author ljwang2
     * @create 2016年8月8日上午11:24:00
     * @version 1.0
     */
    public static boolean createFile(String destFileName) {
        File file = new File(destFileName);
        if (file.exists()) {
            //logger.info("创建单个文件" + destFileName + "失败，目标文件已存在！");
            return false;
        }
        if (destFileName.endsWith(File.separator)) {
            logger.info("创建单个文件" + destFileName + "失败，目标文件不能为目录！");
            return false;
        }
        // 判断目标文件所在的目录是否存在
        if (!file.getParentFile().exists()) {
            // 如果目标文件所在的目录不存在，则创建父目录
            //System.out.println("目标文件所在目录不存在，准备创建它！");
            if (!file.getParentFile().mkdirs()) {
                logger.info("创建目标文件所在目录失败！");
                return false;
            }
        }
        // 创建目标文件
        try {
            if (file.createNewFile()) {
                //System.out.println("创建单个文件" + destFileName + "成功！");
                return true;
            } else {
                logger.info("创建单个文件" + destFileName + "失败！");
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("创建单个文件" + destFileName + "失败！" + e.getMessage());
            return false;
        }
    }

    /**
     * @param destDirName String
     * @return boolean
     * @description 创建目录
     * @author ljwang2
     * @create 2016年8月8日上午11:24:20
     * @version 1.0
     */
    public static boolean createDir(String destDirName) {
        File dir = new File(destDirName);
        if (dir.exists()) {
            //logger.info("创建目录" + destDirName + "失败，目标目录已经存在");
            return false;
        }
        if (!destDirName.endsWith(File.separator)) {
            destDirName = destDirName + File.separator;
        }
        // 创建目录
        if (dir.mkdirs()) {
            System.out.println("创建目录" + destDirName + "成功！");
            return true;
        } else {
            System.out.println("创建目录" + destDirName + "失败！");
            return false;
        }
    }

    /**
     * @param prefix  String
     * @param suffix  String
     * @param dirName String
     * @return String
     * @description
     * @author ljwang2
     * @create 2016年8月8日上午11:24:40
     * @version 1.0
     */
    public static String createTempFile(String prefix, String suffix,
                                        String dirName) {
        File tempFile = null;
        if (dirName == null) {
            try {
                // 在默认文件夹下创建临时文件
                tempFile = File.createTempFile(prefix, suffix);
                // 返回临时文件的路径
                return tempFile.getCanonicalPath();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("创建临时文件失败！" + e.getMessage());
                return null;
            }
        } else {
            File dir = new File(dirName);
            // 如果临时文件所在目录不存在，首先创建
            if (!dir.exists()) {
                if (!FileUtil.createDir(dirName)) {
                    logger.info("创建临时文件失败，不能创建临时文件所在的目录！");
                    return null;
                }
            }
            try {
                // 在指定目录下创建临时文件
                tempFile = File.createTempFile(prefix, suffix, dir);
                return tempFile.getCanonicalPath();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("创建临时文件失败！" + e.getMessage());
                return null;
            }
        }
    }

    public static String readFile(String fileName, String charset) {
        String fileContent = "";
        try {
            File f = new File(fileName);
            if (f.isFile() && f.exists()) {
                InputStreamReader read = new InputStreamReader(
                        new FileInputStream(f), charset);
                BufferedReader reader = new BufferedReader(read);
                String line;
                while ((line = reader.readLine()) != null) {
                    fileContent += line;
                }
                read.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileContent;
    }

    public static void writeFile(String fileName, String fileContent,
                                 String charset) {
        try {
            File f = new File(fileName);
            if (!f.exists()) {
                f.createNewFile();
            }
            OutputStreamWriter write = new OutputStreamWriter(
                    new FileOutputStream(f), charset);
            BufferedWriter writer = new BufferedWriter(write);
            writer.write(fileContent);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static String writeByteFile(String fileName, byte[] data) {
        File f = new File(fileStoreTempPath + fileName);
        try {
            if (!f.exists()) {
                createFile(fileStoreTempPath + fileName);
            }
            FileOutputStream outputStream = new FileOutputStream(f);
            outputStream.write(data);
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileStoreTempPath + fileName;
    }

    /**
     * @param inputFilePath
     * @param extension
     * @return
     * @description 修改文件后缀名
     * @author wangt
     * @create 2017年4月9日下午8:46:05
     * @version 1.0
     */
    public static String modifyFileExtension(String inputFilePath,
                                             String extension) {
        int index = inputFilePath.lastIndexOf(".");
        String mc = inputFilePath.substring(0, index);
        String outputFilePath = mc + "." + extension;
        return outputFilePath;
    }

    /**
     * @param inputFilePath
     * @return
     * @throws IOException
     * @description 实现txt的ANSI格式转成utf-8
     * @author haozhang15
     * @create 2017年8月30日16:53:13
     * @version 1.0
     */
    public static String txtGbk2utf(String inputFilePath) throws IOException {
        /*
         * 文件由ANSI转化为UTF-8 需要用到流InputStreamReader和OutputStreamWriter
         * 这两个流有charset功能
         */
        File srcFile = new File(
                inputFilePath);
        int index = inputFilePath.lastIndexOf(".");
        String mc = inputFilePath.substring(0, index);
        String destFilePath = mc + "utf8" + inputFilePath.substring(index, inputFilePath.length());
        File destFile = new File(
                destFilePath);
        InputStreamReader isr = new InputStreamReader(new FileInputStream(
                srcFile), "GBK"); // ANSI编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
                destFile), "UTF-8"); // 存为UTF-8

        int len = isr.read();
        while (-1 != len) {

            osw.write(len);
            len = isr.read();
        }
        // 刷新缓冲区的数据，强制写入目标文件
        osw.flush();
        osw.close();
        isr.close();
        return destFilePath;
    }

    /**
     * @param inputFilePath
     * @return
     * @description 获取文件后缀名
     * @author hzhang
     * @create 2017年7月10日13:52:04
     * @version 1.0
     */
    public static String getFileSuffixName(String inputFilePath) {
        return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1, inputFilePath.length());
    }

    /**
     * @param inputFilePath
     * @return
     * @description 生成pdf转图片的文件目录（去除后缀）
     * @author hzhang
     * @create 2017年7月10日13:52:04
     * @version 1.0
     */
    public static String getFileExtName(String inputFilePath) {
        return inputFilePath.substring(0, inputFilePath.lastIndexOf("."));
    }


    /**
     * @param remoteFilePath
     * @param localFilePath
     * @return
     * @description 根据FDFS下载文件
     * @author haozhang15
     * @create 2017年6月13日16:28:59
     * @version
     */
    public static void downloadFile(String remoteFilePath, String localFilePath) {
        URL urlfile = null;
        HttpURLConnection httpUrl = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            File f = new File(localFilePath);
            if (!f.getParentFile().exists()) {
                if (!f.getParentFile().mkdirs()) {
                    System.out.println("创建目标文件所在目录失败！");
                }
            }
            urlfile = new URL(remoteFilePath);
            httpUrl = (HttpURLConnection) urlfile.openConnection();
            httpUrl.connect();
            bis = new BufferedInputStream(httpUrl.getInputStream());
            bos = new BufferedOutputStream(new FileOutputStream(f));
            int len = 2048;
            byte[] b = new byte[len];
            while ((len = bis.read(b)) != -1) {
                bos.write(b, 0, len);
            }
            bos.flush();
            bis.close();
            httpUrl.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 质证文件夹的更新与创建
     *
     * @param file
     * @param conent
     * @param flag   2018年1月5日
     *               Administrator
     */
    public static void writeDocNameFile(String file, String conent, Integer flag) {
        if (flag == 1) {
            File file1 = new File(file);
            if (file1.exists() && file1.isFile()) {
                file1.delete();
            }
        }
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(file, true)));
            out.write(conent);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static String readTxtFile(String filePath) {
        String printTxt = "";
        try {
            String encoding = "GBK";
            File file = new File(filePath);
            if (file.isFile() && file.exists()) {// 判断文件是否存在
                InputStreamReader read = new InputStreamReader(
                        new FileInputStream(file), encoding);// 考虑到编码格式
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = null;
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    printTxt = printTxt + lineTxt;
                }
                read.close();
            } else {
                System.out.println("找不到指定的文件");
                logger.info("找不到指定的文件");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return printTxt;

    }

    /**
     * @param @param  fileName
     * @param @return
     * @param @throws Exception    设定文件
     * @return String    返回类型
     * @throws
     * @Description:解压文件
     * @author haozhang15
     * @date 2018年11月30日 上午10:59:54
     */
    public static String unZip(String caseId, String fileName) throws Exception {
        String path = fileStoreTempPath + caseId + "/" + fileName;
        String destDirPath = fileStoreTempPath + caseId + "/";
        File srcFile = new File(path);
        long start = System.currentTimeMillis();
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
        }
        // 开始解压
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcFile, Charset.forName("GBK"));
            Enumeration<?> entrie = zipFile.entries();
            while (entrie.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entrie.nextElement();
            }
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 如果是文件夹，就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = fileStoreTempPath + caseId + "/" + entry.getName();
                    File dir = new File(dirPath);
                    if (!dir.exists()) {
                        dir.mkdirs();
                    }

                } else {
                    // 如果是文件，就先创建一个文件，然后用io流把内容copy过去
                    File targetFile = new File(fileStoreTempPath + caseId + "/" + entry.getName());

                    // 保证这个文件的父文件夹必须要存在
                    if (!targetFile.getParentFile().exists()) {
                        targetFile.getParentFile().mkdirs();
                    }
                    if (!targetFile.exists()) {
                        targetFile.createNewFile();
                        // 将压缩文件内容写入到这个文件中
                        InputStream is = zipFile.getInputStream(entry);
                        FileOutputStream fos = new FileOutputStream(targetFile);
                        int len;
                        byte[] buf = new byte[1024];
                        while ((len = is.read(buf)) != -1) {
                            fos.write(buf, 0, len);
                        }
                        // 关流顺序，先打开的后关闭
                        fos.close();
                        is.close();
                    }
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("解压完成，耗时：" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return destDirPath;
    }

    public static void zip(File file, String targetFileName) {
        zip(Arrays.asList(file), targetFileName);
    }

    public static void zip(List<File> files, String targetFile) {
        if (CollectionUtils.isEmpty(files)) {
            logger.info("源文件空！");
            return;
        }
        long beginTime = System.currentTimeMillis();
        FileOutputStream fis = null;
        ZipOutputStream zos = null;
        try {
            File tarFile = new File(targetFile + ".zip");
            if (tarFile.exists()) {
                tarFile.delete();
            }
            tarFile.createNewFile();
            fis = new FileOutputStream(tarFile);
            zos = new ZipOutputStream(fis);
            zip(files, zos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != fis) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != zos) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        logger.debug("压缩文件总耗时{}毫秒", System.currentTimeMillis() - beginTime);
    }

    private static void zip(List<File> files, ZipOutputStream zos) throws IOException {

        byte[] buff = new byte[1024];
        for (File file : files) {
            String name = file.getName();
            if (file.isDirectory()) {
                File[] fileArr = file.listFiles();
                if (fileArr == null || fileArr.length == 0) {
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    zos.closeEntry();
                    continue;
                }
                zip(Arrays.asList(fileArr), zos);
            }
            logger.debug("开始压缩{}文件", name);
            zos.putNextEntry(new ZipEntry(name));
            int count;
            FileInputStream fis = new FileInputStream(file);
            while ((count = fis.read(buff)) != -1) {
                zos.write(buff, 0, count);
            }
            fis.close();
            zos.closeEntry();
        }
        zos.finish();
    }


    /**
     * @param @param  fileName
     * @param @return 设定文件
     * @return boolean    返回类型
     * @throws
     * @Description:删除目录或者文件
     * @author haozhang15
     * @date 2018年11月30日 上午10:58:03
     */
    public static boolean delete(String fileName) {
        File file = new File(fileStoreTempPath + fileName);
        if (!file.exists()) {
            System.out.println("删除文件失败:" + fileName + "不存在！");
            return false;
        } else {
            if (file.isFile()) {
                return deleteFile(fileStoreTempPath + fileName);
            } else {
                return deleteDirectory(fileStoreTempPath + fileName);
            }
        }
    }

    /**
     * @param @param  fileName
     * @param @return 设定文件
     * @return boolean    返回类型
     * @throws
     * @Description:删除单个文件
     * @author haozhang15
     * @date 2018年11月30日 上午10:57:56
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        // 如果文件路径所对应的文件存在，并且是一个文件，则直接删除
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                System.out.println("删除单个文件" + fileName + "成功！");
                return true;
            } else {
                System.out.println("删除单个文件" + fileName + "失败！");
                return false;
            }
        } else {
            System.out.println("删除单个文件失败：" + fileName + "不存在！");
            return false;
        }
    }

    public static boolean isExist(String fileName) {
        File file = new File(fileName);
        return file.exists();
    }

    /**
     * @param @param  dir
     * @param @return 设定文件
     * @return boolean    返回类型
     * @throws
     * @Description:删除目录
     * @author haozhang15
     * @date 2018年11月30日 上午10:57:38
     */
    public static boolean deleteDirectory(String dir) {
        // 如果dir不以文件分隔符结尾，自动添加文件分隔符
        if (!dir.endsWith(File.separator))
            dir = dir + File.separator;
        File dirFile = new File(dir);
        // 如果dir对应的文件不存在，或者不是一个目录，则退出
        if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
            System.out.println("删除目录失败：" + dir + "不存在！");
            return false;
        }
        boolean flag = true;
        // 删除文件夹中的所有文件包括子目录
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            // 删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag)
                    break;
            }
            // 删除子目录
            else if (files[i].isDirectory()) {
                flag = deleteDirectory(files[i]
                        .getAbsolutePath());
                if (!flag)
                    break;
            }
        }
        if (!flag) {
            System.out.println("删除目录失败！");
            return false;
        }
        // 删除当前目录
        if (dirFile.delete()) {
            System.out.println("删除目录" + dir + "成功！");
            return true;
        } else {
            return false;
        }
    }


    public static void appendFile(String fileName, String fileContent) {
        appendFile(fileName, fileContent, "utf-8");
    }


    public static void appendFile(String fileName, String fileContent, String charset) {
        OutputStreamWriter write = null;
        BufferedWriter writer = null;
        try {
            File f = new File(fileName);
            if (!f.exists()) {
                return;
            }
            write = new OutputStreamWriter(new FileOutputStream(f, true), charset);
            writer = new BufferedWriter(write);
            writer.append(fileContent);
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.toString());
        } finally {
            if (null != write) {
                try {
                    write.close();
                } catch (IOException e) {
                    logger.error(e.toString());
                }
            }
            if (null != writer) {
                try {
                    writer.close();
                } catch (IOException e) {
                    logger.error(e.toString());
                }
            }
        }
    }


    /**
     * 文件拷贝
     *
     * @param oldPath 源文件
     * @param newPath 目标文件
     * @throws IOException
     */
    public static void copyFile(String oldPath, String newPath) {
        File src = new File(oldPath);
        File dest = new File(newPath);
        if (!src.exists()) {
            logger.error("该文件不存在,oldPath={}", oldPath);
        }
        if (!dest.exists()) {
            logger.info("创建文件,newPath={}", newPath);
            try {
                dest.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        copyFile(src, dest);
    }

    /**
     * 文件拷贝
     *
     * @param oldPath 源文件对象
     * @param newPath 目标文件对象
     */
    private static void copyFile(File oldPath, File newPath) {
        //选择流
        InputStream is = null;
        OutputStream os = null;
        try {
            is = Files.newInputStream(oldPath.toPath());
            os = Files.newOutputStream(newPath.toPath());
            //拷贝  循环+读取+写出
            byte[] flush = new byte[1024 * 4];
            int len = 0;
            //读取
            while (-1 != (len = is.read(flush))) {
                //写出
                os.write(flush, 0, len);
            }
            os.flush();//强制刷出
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流  先打开后关闭
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 根据流文件写入
     *
     * @param inputStream         输入流
     * @param newSummaryNotesPath 新路径
     */
    public static void copyFileByInput(InputStream inputStream, String newSummaryNotesPath) {
        FileOutputStream outputStream = null;
        try {
            // 创建文件夹
            String path = newSummaryNotesPath.substring(0, newSummaryNotesPath.lastIndexOf(File.separator));
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            outputStream = new FileOutputStream(newSummaryNotesPath);
            int len = 0;
            byte[] data = new byte[1024];
            while ((len = inputStream.read(data)) != -1) {
                outputStream.write(data, 0, len);
            }
            outputStream.flush();
            logger.info("文件写入成功，文件名:{}", newSummaryNotesPath);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流  先打开后关闭
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 重命名文件
     *
     * @param path    文件路径
     * @param oldName old名字
     * @param newName new名字
     * @return 新文件路径
     */
    public static String renameFile(String path, String oldName, String newName) {
        if (!oldName.equals(newName)) {
            File oldFile = new File(path + File.separator + oldName);
            File newFile = new File(path + File.separator + newName);
            if (newFile.exists()) {
                logger.error("已存在待命名的新文件");
            } else {
                oldFile.renameTo(newFile);
            }

        }
        return path + File.separator + newName;
    }

}